//--------------------------------------------------
/**
 *
 *      Hand Gesture Recognition System
 *
 */
//--------------------------------------------------
/**
 * //HGR CLASS//
 * Librería de captura, pre-procesamiento y procesamiento del sistema
 *
 * @author  Edwin Cobos & Cesar Murcia & Wilson Sarmiento
 * @version HGR_v1.3
 *
 * Revisado: 12/11/11
 */
//--------------------------------------------------
//PACKAGE//
package HGR;
//IMPORT//
import OpenCV.cv;
import OpenCV.cv.IplImage;
import com.sun.jna.Memory;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;


//--------------------------------------------------
/**
 *HGR Class Integra los procesos de captura y procesamiento del <b>Hand Gesture Recognition System</b>
 */
public class HGR
{
    //--------------------------------------------------
    //JFrame
    /**
     * JFrame - Buffer de salida
     */
    public static BufferedImage img = null;
    /**
     * JFrame - Marco de la ventana de salida
     */
    public static JFrame frame;
    /**
     * JFrame - Etiqueta de la ventana de salida
     */
    public static JLabel label;
    /**
     * JFrame - Icono de la ventana de salida
     */
    public static ImageIcon images;

    //--------------------------------------------------
    //Variables de trabajo
    /**
     * Puntero de entrada de la cámara
     */
    public static Pointer camDev;
    /**
     * Número de Frames almacenados en el buffer de <b>Background Subtraction</b>
     */
    public static int frames = 10;
    /**
     * Bandera de salida del sistema
     */
    public static int salida = 0;
    /**
     * Ancho de la imagen
     */
    public static int W;
    /**
     * Alto de la imagen
     */
    public static int H;
    /**
     * Longitud del arreglo de la imagen <b>(W*H)</b>
     */
    public static int L;
    /**
     * Variable para obtener los datos del frame actual
     */
    public static IplImage image_ptr;
    /**
     * Array en el cual se va a almacenar los datos del frame
     */
    public static float[] buffer;
    /**
     * Array de la imagen original para la máscara
     */
    public static float[] bufferOrigin;
    /**
     * Pointer en el cual se va a almacenar el frame en escala de grises
     */
    public static Pointer image_gray;
    /**
     * Array de la imagen de destino para las etiquetas
     */
    public static float[] img_label;
    /**
     * Arreglo en <b>Byte[]</b> de la imagen
     */
    public static byte[] bufferByte;

    public static float[] labels;

    //--------------------------------------------------
    //Variables Background Subtraction
    /**
     * Promedio de la imagen de fondo
     */
    public static float avgBG=0.0f;
    /**
     * Mediana de la imagen de fondo
     */
    public static float varBG=0.0f;
    /**
     * Imagen de fondo
     */
    public static float[] bufferBg;
    /**
     * Imagen resultado del <b>Background Subtraction</b>
     */
    public static float[] bufferBgS;
    /**
     * Umbral para la binarización, entre <b>(0-1)</b>
     */
    public static float Threshold = 0.37f;

    //--------------------------------------------------
    /**
     * Proceso principal de HGR de acuerdo al árbol de procesos.
     * @param args Argumento Línea de Comando
     */
    public static void main(String[] args)
    {
        //Inicializar OpenCV
        cv.loadHighgui();
        cv.loadCv();
        cv.loadCxcore();
        //Inicializar Proceso
        Camera();
        Iniciar();
        int time = 0;   //Contador de los frames

        long tiempoInicio = System.currentTimeMillis();
        //Bucle de proceso frame a frame
        while(true)
        {
            buffer = Core.CaptureFrame(camDev, image_gray, L);   //Obtiene el frame actual en buffer[]
            //Pointer f = cv.createImage(320, 240, 8, 3);
            //cv.Resize(cv.queryFrame(camDev), f, 0);
            cv.showImage("prb", image_gray);
            /*System.arraycopy(buffer, 0, bufferOrigin, 0, L);    //Se hace una copia del frame actual de buffer[] a bufferOrigin[]
            buffer = Core.LowPassFilter(buffer, Core.lp_kernel, W, H);   //Aplica filtro Pasa-Bajos a buffer[]
            buffer = Core.MedianFilter(buffer, 3, W, H);    //Aplica filtro Mediana a buffer[]*/

            ///////

            /*if(time == 0)
            {
                System.out.println("Nuevo BGS, "+time);
                System.arraycopy(buffer, 0, bufferBg, 0, L);    //Se hace una copia del frame actual de buffer[] a bufferOrigin[]
            }else
            {
                for(int k=0; k<bufferBg.length; k++)
                {
                    bufferBg[k] = (bufferBg[k]+buffer[k])/2;
                }
                if(time == 9)
                {
                    time = 0;
                }
            }*/
            /*avgBG = Core.avgImage(bufferBg);    //Almacena el promedio del fondo del BGS
            varBG = Core.varImage(bufferBg, avgBG); //Almacena la mediana del fondo del BGS


            Core.BackgroundSubtractionLearning(buffer, bufferBg, bufferBgS, avgBG, varBG, Threshold);//Realiza el Background substration  entre buffer[] y bufferBG[]
                       
            bufferBgS = Core.DilatationFilter(Core.kernel5_Diamond, bufferBgS, W, H);//Aplica filtro de dilatacion a bufferBgS[]
            bufferBgS = Core.ErosionFilter(Core.kernel5_Diamond, bufferBgS, W, H); //Aplica filtro de Erosion a bufferBgS[]
            */
             /*bufferBgS = Core.DilatationFilter(Core.kernel3_Cross, bufferBgS, W, H);//Aplica filtro de dilatacion a bufferBgS[]
            bufferBgS = Core.ErosionFilter(Core.kernel3_Cross, bufferBgS, W, H); //Aplica filtro de Erosion a bufferBgS[]
            bufferBgS = Core.DilatationFilter(Core.kernel3_Diamond0, bufferBgS, W, H);//Aplica filtro de dilatacion a bufferBgS[]
            bufferBgS = Core.ErosionFilter(Core.kernel3_Diamond0, bufferBgS, W, H); //Aplica filtro de Erosion a bufferBgS[]
             *
             */

            //----TEMP
            /*for(int k=0; k<bufferByte.length; k++)
            {
                bufferByte[k] = (byte)bufferBgS[k];
            }
            Core.byte2Pointer(image_gray, bufferByte);
            cv.showImage("prb0", image_gray);
            //----
            
            labels = Core.LabeledRegions(img_label, bufferBgS, W, H);   //Calcula las regiones en labels[] y las etiquetas en img_label[]
            Core.RemoveRegions(img_label, labels,W,H);  //Remueve las regiones dejando únicamente la más grande
            
            img_label = Core.MaskImage(img_label, bufferOrigin); //Aplica una máscara de img_label a bufferOrigin[]
*/
            /*FloatArray2D Desc1 = new FloatArray2D(img_label, W, H);
            Surf.run(Desc1);*/

            //List<InterestPoint> ipts = IJFacade.getLastResult();
            /*for(int k=0; k<ipts.size(); k++)
            {
                System.out.println(ipts.get(k));
            }*/


            //----TEMP
            /*for(int k=0; k<bufferByte.length; k++)
            {
                bufferByte[k] = (byte)img_label[k];
            }
            Core.byte2Pointer(image_gray, bufferByte);*/
            //cv.showImage("prb", image_gray);
            //----
            int key = cv.waitKey(30);
            //System.out.println(key);
            if(key==27) //ESC
                salida=1;
            if(key == 2555904)//Flecha Derecha
            {
                Threshold += 0.01f;
                System.out.println(Threshold);
            }
            if(key == 2424832)//Flecha Izquierda
            {
                Threshold -= 0.01f;
                System.out.println(Threshold);
            }            
            if(salida == 1)
                break;
            time++;
        }
        long totalTiempo = System.currentTimeMillis() - tiempoInicio;
        System.out.println("El tiempo es : " + totalTiempo + " miliseg");

        System.out.println("Fin");
        System.exit(0);                
    }

    //--------------------------------------------------
    /**
     * Accede al dispositivo y comprueba su disponibilidad
     */
    public static void Camera()
    {
        System.out.print("");
        camDev = cv.createCameraCapture(0);
        if(camDev==null)
        {
            System.out.println("No camera conected");
            //System.exit(0);
        }
        else
        {
            System.out.println("Camera conected");
        }
    }
    
    public static void FinCamera()
    {
        System.out.println("Free Camera");               
        cv.releaseCapture(camDev.NULL);
        //camDev = null;
    }



    //--------------------------------------------------
    /**
     * Crea una ventana de tipo <b>JFrame</b> para visualización en java
     * @param name Titulo de la ventana
     */
    public static void MakeJWindow(String name)
    {
        JFrame.setDefaultLookAndFeelDecorated(true);
        frame = new JFrame(name);
        label = new JLabel();
        frame.getContentPane().add(label, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        frame.setVisible(true);
        
        frame.addWindowListener(new WindowAdapter()
        {@Override
            public void windowClosing(WindowEvent winEvt)
            {
                salida = 1;
            }
        });
    }

    //--------------------------------------------------
    /**
     * Actualiza el buffer en la ventana de <b>JFrame</b>
     */
    public static void Update()
    {
        images = new ImageIcon(img);
        label.setIcon(images);        
        frame.pack();
    }

    //--------------------------------------------------
    /**
     * Inicializa las variables de proceso
     */
    public static void Iniciar()
    {
        //image_ptr = new IplImage(cv.queryFrame(camDev));    //Captura del frame actual

        Pointer f = cv.createImage(320, 240, 8, 3);
        cv.Resize(cv.queryFrame(camDev), f, 0);
        image_ptr = new IplImage(f);
        H = image_ptr.height;   //Alto
        W = image_ptr.width;    //Ancho
        L = W * H;              //Longitud
        //buffer = new float[L];  //Array de trabajo
        bufferOrigin = new float[L];    //Array original para enmascarado
        image_gray = cv.createImage(W, H, 8, 1);    //Puntero del frama para la conversion a grises
        bufferBgS = new float[L];   //Array para almacenar el Background substration
        //bufferBg = new float[L];
        //bufferBg = Core.MakeBufferBg(Core.lp_kernel, camDev, buffer, frames, L, W, H); // Array para almacenar el fondo del BGS
        //avgBG = Core.avgImage(bufferBg);    //Almacena el promedio del fondo del BGS
        //varBG = Core.varImage(bufferBg, avgBG); //Almacena la mediana del fondo del BGS
        img_label = new float[L];   //Array para trabajar el frame con el proceso de etiquetado
        bufferByte = new byte[L];   //Array para trabajar el frame en byte
    }

}
//--------------------------------------------------
//FIN
//--------------------------------------------------